package com.xiaoxin.experience.system.log;

import com.xiaoxin.experience.common.BaseResponse;
import com.xiaoxin.experience.common.BusinessException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.Objects;

/**
 * create by xiaoxin on 2021/3/13
 */
public class MethodAspectHelper
{
    private static final Logger log = LoggerFactory.getLogger(MethodAspectHelper.class);

    private final ProceedingJoinPoint joinPoint;

    private final MethodSignature signature;

    private final String methodFullName;

    private final Object[] params;

    public MethodAspectHelper(ProceedingJoinPoint pjp)
    {
        this.joinPoint = pjp;
        signature = (MethodSignature)pjp.getSignature();
        String methodName = signature.getName();
        String className = pjp.getTarget().getClass().getName();
        this.methodFullName = className + "." + methodName;
        Class<?>[] paramTypes = signature.getParameterTypes();
        params = pjp.getArgs();
    }

    public <T extends Annotation> T getMethodAnnotation(Class<T> annotationClass)
    {
        return signature.getMethod().getAnnotation(annotationClass);
    }

    public void logEnter()
    {
        log.info((">>> Enter " + methodFullName));

        if (log.isDebugEnabled())
        {
            StringBuilder builder = new StringBuilder("Parameters:[");
            if (null != params && params.length > 0)
            {
                for (int i = 0; i < params.length; i++)
                {
                    Object arg = params[i];
                    builder.append(arg);
                    if (i < params.length - 1)
                    {
                        builder.append(", ");
                    }
                }
            }
            builder.append("]");
            log.debug(builder.toString());
        }
    }

    public Object logExecute()
            throws Throwable
    {
        logEnter();
        try
        {
            Object response = this.joinPoint.proceed();
            log.debug("return [{}]",response);
            return response;
        }
        catch (Exception e)
        {
            Object returnObject = getReturnObject();
            return errorHandle(e,returnObject);
        }
        finally
        {
            log.info((">>> Leave " + methodFullName));
        }
    }

    private Object errorHandle(Exception e, Object response)
    {
        if (Objects.isNull(response))
        {
            return null;
        }
        if (response instanceof BaseResponse)
        {
            log.error("error detail :",e);
            BaseResponse baseResponse = (BaseResponse)response;
            if (e instanceof BusinessException)
            {
                BusinessException businessException = (BusinessException)e;
                baseResponse.setResultCode(businessException.getError());
                baseResponse.setResultDesc(businessException.getMessage());
            }
            else
            {
                baseResponse.setResultCode(-1);
                baseResponse.setResultDesc(e.getMessage());
            }
        }
        log.debug("error return [{}]", response);
        return response;
    }

    private Class<?> getReturnType()
    {
        return signature.getMethod().getReturnType();
    }

    private Object getReturnObject()
    {
        Object retObject = null;
        try
        {
            Class<?> retClass = getReturnType();
            retObject = retClass.newInstance();
        }
        catch (Exception e)
        {
            log.warn("getReturnObject class newInstance fail: {}", e.getMessage());
        }
        return retObject;
    }
}

